#include "src/emule/parse_server_met.h"
#include <assert.h>
#include "src/error_code.h"
#include "emule_define.h"
#include "src/utility/conversion.h"
#include "src/utility/log.h"

jellyfish::emule::parse_server_met::parse_server_met()
{

}

jellyfish::emule::parse_server_met::~parse_server_met()
{

}

int32 jellyfish::emule::parse_server_met::parse( const char* file_path )
{
	int32 result = open(file_path);
	if (result != succeeded)
	{
		return file_not_valid;
	}

	result = is_met_file();
	if (result != succeeded)
	{
		return result;
	}

	uint32 fservercount = file_.read_t<uint32>();

	server_block_struct server_block;
	tag_struct tag;
	for ( uint32 j = 0; j < fservercount; ++j ) 
	{
		server_block.clear();
		server_block.ip = file_.read_t<uint32>();
		server_block.port = file_.read_t<uint16>();
		uint32 tag_count = file_.read_t<uint32>();
		for (uint32 i = 0; i < tag_count ; ++i)
		{
			read_tag(&tag,&server_block);
		}
		print_server_information(server_block);
		servers_.push_back(server_block);		
	}
	return succeeded;
}
void jellyfish::emule::parse_server_met::print_server_information( const server_block_struct& server_block )
{
	LOG_DEBUG("ip:"<<utility::int_to_ip(server_block.ip).c_str());
	LOG_DEBUG("port:"<<server_block.port);
	LOG_DEBUG("server name:"<<server_block.server_name.c_str());
	LOG_DEBUG("server description:"<<server_block.server_description.c_str());
	LOG_DEBUG("ping time:"<<server_block.ping_time);
	LOG_DEBUG("failed times:"<<server_block.failed_times);
	LOG_DEBUG("preference:"<<server_block.preference);
	LOG_DEBUG("DNS:"<<server_block.dns.c_str());
	LOG_DEBUG("max users:"<<server_block.max_users);
	LOG_DEBUG("soft files:"<<server_block.soft_files);
	LOG_DEBUG("hard files:"<<server_block.hard_files);
	LOG_DEBUG("last ping:"<<server_block.last_ping);
	LOG_DEBUG("version:"<<server_block.version.c_str());
	LOG_DEBUG("UDP flags:"<<server_block.udp_flags);
	LOG_DEBUG("auxiliary ports list:"<<server_block.auxiliary_ports_list.c_str());
	LOG_DEBUG("LOW ID clients:"<<server_block.lowid_clients);
	LOG_DEBUG("files:"<<server_block.files);
	LOG_DEBUG("users:"<<server_block.users);
	LOG_DEBUG("");
}
void jellyfish::emule::parse_server_met::read_tag( tag_struct* tag,server_block_struct* server)
{
	tag->clear();
	tag->type = file_.read_t<uint8>();
	if (tag->type & 0x80)
	{
		tag->type &= 0x7F;
		tag->id = file_.read_t<uint8>();
	} 
	else 
	{
		uint16 length = file_.read_t<uint16>();
		if (length == 1) 
		{
			tag->id = file_.read_t<uint8>();
		} 
		else 
		{
			tag->id = 0;
			tag->name = read_ansi_string(length);
		}
	}

	if (tag->type == TAGTYPE_STRING)
	{
		tag->value_string = read_ansi_string(file_.read_t<uint16>());
	}
	else if (tag->type == TAGTYPE_UINT32)
	{
		tag->value_uint64_t = file_.read_t<uint32>();
	}
	else if (tag->type == TAGTYPE_UINT64)
	{
		file_.seek(sizeof(uint64), SEEK_CUR);
	}
	else if (tag->type == TAGTYPE_UINT16)
	{
		file_.seek(sizeof(uint16), SEEK_CUR);
	}
	else if (tag->type == TAGTYPE_UINT8)
	{
		file_.seek(sizeof(uint8), SEEK_CUR);
	}
	else if (tag->type == TAGTYPE_FLOAT32)
	{
		file_.seek(sizeof(float), SEEK_CUR);
	}
	else if (tag->type >= TAGTYPE_STR1 && tag->type <= TAGTYPE_STR16)
	{
		file_.seek(tag->type - TAGTYPE_STR1 + 1, SEEK_CUR);
	}
	else if (tag->type == TAGTYPE_HASH16)
	{
		file_.seek(16, SEEK_CUR);
	}
	else if (tag->type == TAGTYPE_BOOL)
	{
		file_.seek(1, SEEK_CUR);
	}
	else if (tag->type == TAGTYPE_BOOLARRAY)
	{
		uint16 len = 0;
		file_.read(&len, 2);
		file_.seek((len/8)+1,SEEK_CUR);
	}
	else if (tag->type == TAGTYPE_BLOB)
	{
		tag->blob_size = file_.read_t<uint32>();
		if (tag->blob_size <= file_.get_length() - file_.get_position())
		{
			file_.seek(tag->blob_size,SEEK_CUR);
		}
		else
		{
			assert( false );
		}
	}
	else
	{
		tag->value_uint64_t = 0;
	}

	if (tag->id == 0x01)
	{
		server->server_name = tag->value_string;
	}
	else if (tag->id == 0x0b)
	{
		server->server_description = tag->value_string;
	}
	else if (tag->id == 0x0c)
	{
		server->ping_time = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->id == 0x0d)
	{
		server->failed_times = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->id == 0x0e)
	{
		server->preference = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->id == 0x85)
	{
		server->dns = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->id == 0x87)
	{
		server->max_users = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->id == 0x88)
	{
		server->soft_files = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->id == 0x89)
	{
		server->hard_files = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->id == 0x90)
	{
		server->last_ping = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->id == 0x91)
	{
		server->version = tag->value_string;
	}
	else if (tag->id == 0x92)
	{
		server->udp_flags = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->id == 0x93)
	{
		server->auxiliary_ports_list = tag->value_string;
	}
	else if (tag->id == 0x94)
	{
		server->lowid_clients = static_cast<uint32>(tag->value_uint64_t);
	}

	if (tag->name == "files")
	{
		server->files = static_cast<uint32>(tag->value_uint64_t);
	}
	else if (tag->name == "users")
	{
		server->users = static_cast<uint32>(tag->value_uint64_t);
	}
}

int32 jellyfish::emule::parse_server_met::open( const char* file_path )
{
	return file_.open(file_path,"rb") ? succeeded : file_not_valid;
}

int32 jellyfish::emule::parse_server_met::is_met_file()
{
	file_.seek(0,SEEK_SET);
	uint8 version = file_.read_t<uint8>();
	if (version != met_header1 && version != met_header2)
	{
		return file_not_met;
	}
	return succeeded;
}


std::string jellyfish::emule::parse_server_met::read_ansi_string( uint16 raw_len )
{
	char* val_array = new char[raw_len + 1];
	val_array[raw_len] = 0;
	file_.read(val_array,raw_len);
	std::string ret = val_array;
	delete []val_array;
	return ret;
}




//#define CHECK_BOM(size, x) ((size >= 3)  && (x[0] == (char)0xEF) && (x[1] == (char)0xBB) && (x[2] == (char)0xBF))
//std::string jellyfish::emule::parse_server_met::ReadOnlyString( bool bOptUTF8, uint16_t raw_len )
//{
//	char* val_array = new char[raw_len + 1];
//	val_array[raw_len] = 0;
//	file_.read(val_array,raw_len);
//
//	std::string str;
//	if (CHECK_BOM(raw_len, val_array)) {
//		str = utility::utf8_to_unicode(val_array+3,raw_len-3);
//	} 
//	else
//	{
//		str = utility::utf8_to_unicode(val_array,raw_len);
//	}
//	delete []val_array;
//	return str;
//}
//


